package dk.itu.KrakMap;

import graphlib.Edge;
import graphlib.Graph;
import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * A graph edge created from an EdgeData object. 
 * For the sake of memory efficiency a KrakEdge doesnt
 * store all the information available in EdgeData, for example 
 * the zip code and similar are not currently stored.
 * This can easily be changed, by simply adding the necessary fields,and
 * setting their value corresponding to the EdgeData object
 *
 * @author Peter Tiedemann petert@itu.dk
 */
public class KrakEdge extends Edge<KrakNode> implements Road {
    // sestoft: For sharing roadname strings

    private static HashMap<String, String> interner = new HashMap<String, String>();
    private double length;
    //public final int DAV_DK, DAV_DK_ID;
    //public final int type;
    public final RoadType roadType;
    public final String roadname;
    //public final int FROMLEFT;
    //public final int TOLEFT;
    public final int speedLimit;
    //public final int FROMRIGHT;
    //public final int TORIGHT;
    private Color color;
    

    /**
     * This is only made for testing; therefore the strange color!
     * @param a The start node
     * @param b The end node
     * @param t The RoadType
     * @param d The direction
     */
    public KrakEdge(KrakNode a, KrakNode b, RoadType t, Byte d) {
        v1 = a;
        v2 = b;
        length = a.getMapPoint().dist(b.getMapPoint());
        roadType = t;
        roadname = "Test edge!";
        if (t == RoadType.MOTORVEJ) {
            speedLimit = 130;
        } else if (t == RoadType.Primaerrute) {
            speedLimit = 80;
        } else {
            speedLimit = 30;
        }
        color = Color.PINK;
        direction = d;
    }

    public KrakEdge(EdgeData data, Graph<KrakEdge, KrakNode> graph) {
        this.v1 = graph.getNode(data.FNODE);
        this.v2 = graph.getNode(data.TNODE);

    
        speedLimit = data.SPEED;
        length = data.LENGTH;
        //DAV_DK = data.DAV_DK;
        //DAV_DK_ID = data.DAV_DK_ID;
        //type = data.TYP;
        roadType = RoadType.getRoadType(data.TYP);
        // sestoft: Share roadname strings to save space
        String interned = interner.get(data.VEJNAVN);
        if (interned != null) {
            roadname = interned;
        } else {
            roadname = data.VEJNAVN;
            interner.put(roadname, roadname);
        }
        String dir = data.ONE_WAY;
        /*
         * 	tf = ensrettet modsat digitalise�rings�retning (To-From)
         *	ft = ensrettet i digitaliseringsretning (From-To)
         *  n = ingen kørsel tilladt (henholdsvis typ 8, 21-28)
         *  <blank> = ingen ensretning
         */
        if (dir.equalsIgnoreCase("tf")) {
            this.direction = Edge.BACKWARD;
        } else if (dir.equalsIgnoreCase("ft")) {
            this.direction = Edge.FORWARD;
        } else if (dir.equalsIgnoreCase("n")) {
            // FIXME:this road can not be travelled on, shouldn't really be included
            this.direction = Edge.BOTH;
        } else {
            this.direction = Edge.BOTH;
        }
        //FROMLEFT = data.FROMLEFT;
        //TOLEFT = data.TOLEFT;
        //FROMRIGHT = data.FROMRIGHT;
        //TORIGHT = data.TORIGHT;
    }

    public static void clear() {
        interner = null;
    }

    /**
     * Update weight of KrakEdges help the Route-finding algorithm decide how to prioritize it.
     * @param travellerProfile Specified TravellerProfile to update KrakEdges by.
     */
    public void updateWeight(Iterable<TravelType> travellerProfile) {
        this.setWeight(calcWeight(travellerProfile));
    }

    /**
     * @param travellerProfile Specified TravellerProfile to update KrakEdges by.
     * @return Weight calculated using the various TravelTypes.
     */
    private double calcWeight(Iterable<TravelType> travellerProfile) {
        double newWeight = 10000000.0;
        for (TravelType tt : travellerProfile) {
            if (!tt.getExcludedRoadTypes().contains(roadType)) {
                int speed = tt.getSpeedChanges().containsKey(roadType) ? tt.getSpeedChanges().get(roadType) : tt.getMaxSpeed();
                speed = (this.speedLimit < speed) ? this.speedLimit : speed;
                if (speed == 0.0){
                    speed = this.roadType.getSpeed();
                }
                double calcWeight = getLength() / speed;
                if (calcWeight < newWeight) {
                    newWeight = calcWeight;
                }
            }
        }
        return newWeight;
    }

    public String getName() {
        return roadname;
    }

    @Override
    public MapPoint getStart() {
        return new MapPoint(v1.getX(), v1.getY());
    }

    @Override
    public MapPoint getEnd() {
        return new MapPoint(v2.getX(), v2.getY());
    }

    public RoadType getType() {
        return roadType;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color c) {
        this.color = c;
    }

    /**
     * @return the length.
     */
    public double getLength() {
        return length;
    }

    /**
     * @param length the length to set.
     */
    public void setLength(double length) {
        this.length = length;
    }

    /**
     * @return the color.
     */
    public Color getStrokeColor() {
        return roadType.getStrokeColor();
    }

    public double calcAngle(KrakEdge a){
        return calcAngle(this,a);
    }

    private static double calcAngle(KrakEdge e, KrakEdge f) {
        double dotP = 0;
        double eVecX = e.getStart().getX() + e.getEnd().getX();
        double eVecY = e.getStart().getY() + e.getEnd().getY();

        double fVecX = f.getStart().getX() + f.getEnd().getX();
        double fVecY = f.getStart().getY() + f.getEnd().getY();

        dotP = eVecX * fVecX + eVecY * fVecY;
        return Math.cos(dotP);
    }
}
